home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 267_01 / as6.c < prev    next >
Text File  |  1989-01-11  |  13KB  |  504 lines

  1. /*
  2.     HEADER:        CUG267;
  3.     TITLE:        S6 Cross-Assembler (Portable);
  4.     FILENAME:    AS6.C;
  5.     VERSION:    0.2;
  6.     DATE:        08/27/1988;
  7.     SEE-ALSO:    AS6.H;
  8.     AUTHORS:    William C. Colley III;
  9. */
  10.  
  11. /*
  12.                S6 Cross-Assembler in Portable C
  13.  
  14.         Copyright (c) 1986, 1987 William C. Colley, III
  15.  
  16. Revision History:
  17.  
  18. Ver    Date        Description
  19.  
  20. 0.0    NOV 1987    Derived from my 6502 cross-assembler.  WCC3.
  21.  
  22. 0.1    JUNE 1988    Fixed glitches in the relative jumps and in the bit
  23.             operations to make the assembler conform to the
  24.             machine rather than to the machine's documentation.
  25.             WCC3.
  26.  
  27. 0.2    AUG 1988    Fixed a bug in the command line parser that puts it
  28.             into a VERY long loop if the user types a command line
  29.             like "AS6 FILE.ASM -L".  WCC3 per Alex Cameron.
  30.  
  31. This file contains the main program and line assembly routines for the
  32. assembler.  The main program parses the command line, feeds the source lines
  33. to the line assembly routine, and sends the results to the listing and object
  34. file output routines.  It also coordinates the activities of everything.  The
  35. line assembly routines uses the expression analyzer and the lexical analyzer
  36. to parse the source line and convert it into the object bytes that it
  37. represents.
  38. */
  39.  
  40. /*  Get global goodies:  */
  41.  
  42. #include "as6.h"
  43.  
  44. /*  Define global mailboxes for all modules:                */
  45.  
  46. char errcode, line[MAXLINE + 1], title[MAXLINE];
  47. int pass = 0;
  48. int eject, filesp, forwd, listhex;
  49. unsigned address, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
  50. FILE *filestk[FILES], *source;
  51. TOKEN token;
  52.  
  53. /*  Mainline routine.  This routine parses the command line, sets up    */
  54. /*  the assembler at the beginning of each pass, feeds the source text    */
  55. /*  to the line assembler, feeds the result to the listing and hex file    */
  56. /*  drivers, and cleans everything up at the end of the run.        */
  57.  
  58. static int done, ifsp, off;
  59.  
  60. void main(argc,argv)
  61. int argc;
  62. char **argv;
  63. {
  64.     SCRATCH unsigned *o;
  65.     int newline();
  66.     void asm_line();
  67.     void lclose(), lopen(), lputs();
  68.     void hclose(), hopen(), hputc();
  69.     void error(), fatal_error(), warning();
  70.  
  71.     printf("S6 Cross-Assembler (Portable) Ver 0.2\n");
  72.     printf("Copyright (c) 1986, 1987 William C. Colley, III\n\n");
  73.  
  74.     while (--argc > 0) {
  75.     if (**++argv == '-') {
  76.         switch (toupper(*++*argv)) {
  77.         case 'L':   if (!*++*argv) {
  78.                 if (!--argc) { warning(NOLST);  break; }
  79.                 else ++argv;
  80.                 }
  81.                 lopen(*argv);
  82.                 break;
  83.  
  84.         case 'O':   if (!*++*argv) {
  85.                 if (!--argc) { warning(NOHEX);  break; }
  86.                 else ++argv;
  87.                 }
  88.                 hopen(*argv);
  89.                 break;
  90.  
  91.         default:    warning(BADOPT);
  92.         }
  93.     }
  94.     else if (filestk[0]) warning(TWOASM);
  95.     else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
  96.     }
  97.     if (!filestk[0]) fatal_error(NOASM);
  98.  
  99.     while (++pass < 3) {
  100.     fseek(source = filestk[0],0L,0);  done = off = FALSE;
  101.     errors = filesp = ifsp = pagelen = pc = 0;  title[0] = '\0';
  102.     while (!done) {
  103.         errcode = ' ';
  104.         if (newline()) {
  105.         error('*');
  106.         strcpy(line,"\tEND\n");
  107.         done = eject = TRUE;  listhex = FALSE;
  108.         bytes = 0;
  109.         }
  110.         else asm_line();
  111.         pc = word(pc + bytes);
  112.         if (pass == 2) {
  113.         lputs();
  114.         for (o = obj; bytes--; hputc(*o++));
  115.         }
  116.     }
  117.     }
  118.  
  119.     fclose(filestk[0]);  lclose();  hclose();
  120.  
  121.     if (errors) printf("%d Error(s)\n",errors);
  122.     else printf("No Errors\n");
  123.  
  124.     exit(errors);
  125. }
  126.  
  127. /*  Line assembly routine.  This routine gets the contents of the    */
  128. /*  argument field from the source file using the expression evaluator    */
  129. /*  and lexical analyzer.  It makes all validity checks on the        */
  130. /*  arguments validity, fills a buffer with the machine code bytes and    */
  131. /*  returns nothing.                            */
  132.  
  133. static char label[MAXLINE];
  134. static int ifstack[IFDEPTH] = { ON };
  135.  
  136. static OPCODE *opcod;
  137.  
  138. void asm_line()
  139. {
  140.     SCRATCH int i;
  141.     int isalph(), popc();
  142.     OPCODE *find_code(), *find_operator();
  143.     void do_label(), flush(), normal_op(), pseudo_op();
  144.     void error(), pops(), pushc(), trash();
  145.  
  146.     address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
  147.     for (i = 0; i < BIGINST; obj[i++] = NOP);
  148.  
  149.     label[0] = '\0';
  150.     if ((i = popc()) != ' ' && i != '\n') {
  151.     if (isalph(i)) {
  152.         pushc(i);  pops(label);
  153.         if (find_operator(label)) { label[0] = '\0';  error('L'); }
  154.     }
  155.     else {
  156.         error('L');
  157.         while ((i = popc()) != ' ' && i != '\n');
  158.     }
  159.     }
  160.  
  161.     trash();  opcod = NULL;
  162.     if ((i = popc()) != '\n') {
  163.     if (!isalph(i)) error('S');
  164.     else {
  165.         pushc(i);  pops(token.sval);
  166.         if (!(opcod = find_code(token.sval))) error('O');
  167.     }
  168.     if (!opcod) { listhex = TRUE;  bytes = BIGINST; }
  169.     }
  170.  
  171.     if (opcod && opcod -> attr & ISIF) { if (label[0]) error('L'); }
  172.     else if (off) { listhex = FALSE;  flush();  return; }
  173.  
  174.     if (!opcod) { do_label();  flush(); }
  175.     else {
  176.     listhex = TRUE;
  177.     if (opcod -> attr & PSEUDO) pseudo_op();
  178.     else normal_op();
  179.     while ((i = popc()) != '\n') if (i != ' ') error('T');
  180.     }
  181.     source = filestk[filesp];
  182.     return;
  183. }
  184.  
  185. static void flush()
  186. {
  187.     while (popc() != '\n');
  188. }
  189.  
  190. static void do_label()
  191. {
  192.     SCRATCH SYMBOL *l;
  193.     SYMBOL *find_symbol(), *new_symbol();
  194.     void error();
  195.  
  196.     if (label[0]) {
  197.     listhex = TRUE;
  198.     if (pass == 1) {
  199.         if (!((l = new_symbol(label)) -> attr)) {
  200.         l -> attr = FORWD + VAL;
  201.         l -> valu = pc;
  202.         }
  203.     }
  204.     else {
  205.         if (l = find_symbol(label)) {
  206.         l -> attr = VAL;
  207.         if (l -> valu != pc) error('M');
  208.         }
  209.         else error('P');
  210.     }
  211.     }
  212. }
  213.  
  214. static void normal_op()
  215. {
  216.     SCRATCH unsigned opcode;
  217.     SCRATCH unsigned op1, op2;
  218.  
  219.     static unsigned reverse3[] = {
  220.     0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0
  221.     };
  222.  
  223.     unsigned get_arg();
  224.     void do_direct(), do_immediate(), do_label(), error();
  225.  
  226.     bytes = opcod -> attr & BYTES;  opcode = opcod -> valu;
  227.     op1 = op2 = 0;  do_label();
  228.     switch (opcod -> attr & OPTYPE) {
  229.     case LDI:    if (get_arg(0) & IS_A) {
  230.                 opcode = 0x17;  bytes = 2;
  231.                 get_arg(1);  do_immediate(&op1);
  232.             }
  233.             else {
  234.                 do_direct(&op1);  get_arg(1);  do_immediate(&op2);
  235.             }
  236.             break;
  237.  
  238.     case ADDI_OP:    if (!(get_arg(0) & IS_A)) error('S');
  239.             else { get_arg(1);  do_immediate(&op1); }
  240.             break;
  241.  
  242.     case JR_SIGN:    op1 = 0xff;  goto do_rel8;
  243.  
  244.     case JR_BIT:    get_arg(0);
  245.             if (token.valu > 7) error('V');
  246.             else opcode |= reverse3[token.valu];
  247.             get_arg(0);  do_direct(&op1);
  248. do_rel8:        get_arg(1);
  249.             if ((op2 = token.valu - (pc + 3)) > 0x7f &&
  250.                 op2 < 0xff80) {
  251.                 error('B');  op2 = 0;
  252.             }
  253.             break;
  254.  
  255.     case JR:    get_arg(1);
  256.             if ((op1 = token.valu - (pc+ 1)) > 0x0f &&
  257.                 op1 < 0xfff0) error('B');
  258.             else opcode |= (op1 << 3) & 0xf8;
  259.             break;
  260.  
  261.     case JP:    get_arg(1);
  262.             if ((op1 = token.valu) > 0x0fff) {
  263.                 error('V');  op1 = 0;
  264.             }
  265.             opcode |= (op1 << 4) & 0x00f0;  op1 >>= 4;
  266.             break;
  267.  
  268.     case LD:    if (get_arg(0) & IS_A) goto do_inc;
  269.             if (token.attr & IS_XYVW) {
  270.                 opcode = 0x3d + ((token.valu & 0x03) << 6);
  271.                 bytes = 1;
  272.             }
  273.             else if (token.attr & IS_IND) {
  274.                 opcode = (token.valu == 0x80) ? 0x87 : 0x8f;
  275.                 bytes = 1;
  276.             }
  277.             else { opcode = 0x9f;  do_direct(&op1); }
  278.             if (!(get_arg(1) & IS_A)) error('S');
  279.             break;
  280.  
  281.     case CLR:    if (get_arg(1) & IS_A) { opcode = 0xdf;  op1 = 0xff; }
  282.             else { bytes = 3;  do_direct(&op1); }
  283.             break;
  284.  
  285.     case BIT_OP:    get_arg(0);
  286.             if (token.valu > 7) error('V');
  287.             else opcode |= reverse3[token.valu];
  288.             get_arg(1);  do_direct(&op1);
  289.             break;
  290.  
  291. do_inc:    case INC_DEC:    if (get_arg(1) & IS_XYVW) {
  292.                 opcode = (opcode >> 8) +
  293.                 ((token.valu & 0x03) << 6);
  294.                 bytes = 1;  break;
  295.             }
  296.             goto do_add;
  297.  
  298.     case ADD_OP:    if (!(get_arg(0) & IS_A)) { error('S');  break; }
  299.             get_arg(1);
  300. do_add:            if (token.attr & IS_IND) {
  301.                 opcode -= (token.valu == 0x80) ? 0x18 : 0x10;
  302.                 bytes = 1;
  303.             }
  304.             else do_direct(&op1);
  305.             break;
  306.  
  307.     case SHIFT_OP:    if (!(get_arg(1) & IS_A)) error('S');
  308.  
  309.     case NO_ARG:    op1 = opcode >> 8;
  310.             break;
  311.     }
  312.     if (bytes > 2) obj[2] = low(op2);
  313.     if (bytes > 1) obj[1] = low(op1);
  314.